#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <libgen.h>
#include <errno.h>

#include "network.h"

#define BUFFER_SIZE 4096

static int port = 23456;
static urllist_t burl;


#include <stdio.h>
#include <string.h>



int gotoxy(int x, int y) {
	char essq[100];		// String variable to hold the escape sequence
	char xstr[100];		// Strings to hold the x and y coordinates
	char ystr[100];		// Escape sequences must be built with characters

	/*
	** Convert the screen coordinates to strings
	*/
	sprintf(xstr, "%d", x);
	sprintf(ystr, "%d", y);

	/*
	** Build the escape sequence (vertical move)
	*/
	essq[0] = '\0';
	strcat(essq, "\033[");
	strcat(essq, ystr);

	/*
	** Described in man terminfo as vpa=\E[%p1%dd
	** Vertical position absolute
	*/
	strcat(essq, "d");
	
	/*
	** Horizontal move
	** Horizontal position absolute
	*/
	strcat(essq, "\033[");
	strcat(essq, xstr);
	// Described in man terminfo as hpa=\E[%p1%dG
	strcat(essq, "G");

	/*
	** Execute the escape sequence
	** This will move the cursor to x, y
	*/
	printf("%s", essq);

	return 0;
}



int _OpenSocket(char *ip, int port)
{
	int s, b, c;
	int so = 1;

	struct sockaddr_in my_addr, dest_addr; 

	s = socket(AF_INET, SOCK_STREAM, 0);
	if(s < 0 ) 
	{
		perror("DW: socket");
		return -1;
	}
	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &so, sizeof(so));
/*
	memset(&my_addr, 0, sizeof(my_addr));

	my_addr.sin_family = AF_INET;
	my_addr.sin_addr.s_addr = INADDR_ANY;
	my_addr.sin_port = htons(port);


	do
	{
		b = bind(s, (struct sockaddr*)&my_addr, sizeof(my_addr));

		if(b < 0)
		{
			perror("DW: Error! open_socket: bind ");
			if(errno == EADDRINUSE) 
			{
				port += 2;
				continue;
			}	
			
			close(s);
			return -1;
		} 
		break;
		
	} while(1);
*/
	if(NULL != ip)
	{
		memset(&dest_addr, 0, sizeof(dest_addr));

		dest_addr.sin_family = AF_INET;
		dest_addr.sin_addr.s_addr = inet_addr(ip);
		dest_addr.sin_port = htons(HTTP_PORT);

		c = connect(s, (struct sockaddr*)&dest_addr, sizeof(struct sockaddr_in));
		if( c < 0) 
		{
			perror("DW: Error! open_socket: connect");
			close(s);
			return -1;
		}
	}

	return s;
}


char * _GetIP(char * url, char *ip){

	char *tmp_ptr = NULL;
	char urls[1024] = "";
	char *domain = NULL;
	char dummy[100] = "";
	char *path = NULL;
	struct hostent *host= NULL;
	char delimn[] = "/";

	strcpy(urls, url);

	if(strncmp(urls, "http://", 7) == 0)
	{
		tmp_ptr = urls + 7;
		domain = strtok(tmp_ptr, delimn);

		strcpy(burl.domain, domain);
		path = url + 7 + strlen(domain);
		strcpy(burl.directory, path);

		host = gethostbyname(domain);
		
		if (host == NULL) 
		{
			printf("DW: Error! Lookup host failed\n");
			ip = NULL;
			return NULL;
		}

		inet_ntop(AF_INET, host->h_addr_list[0], dummy, 100);

		strcpy(ip, dummy);
		strcpy(burl.ip, ip);

	} else 
	{
		printf("DW: Warning! Protocol other than HTTP is not supported.\n");
		ip = NULL;
		return NULL;
	}
	 return ip; 
}


int _SendString(int s, char *string, int length)
{
	int n = 0;
	n = write(s, string, length);
	if(n < 0) perror("DW: Error! send");
	return n;
}


int _RecvHeader(int s, char *buffer, int length)
{
	int n = 0;
	int i = 0;
	while(1)
	{
		n = read(s, &buffer[i], 1);
		if(buffer[i - 3] == '\r' && buffer[i - 2] == '\n' && buffer[i - 1] == '\r' && buffer[i] == '\n') break;
		if(buffer[i - 1] == '\n' && buffer[i] == '\n') break;
		if(buffer[i - 1] == '\r' && buffer[i] == '\r') break;
		if (n < 0 ) break;
		i++;
	}

	if(n < 0) perror("DW: Error! recv header");

	return i;
}


int _parseHeader(char *string, int *code, char *error_string)
{
	int con_len = 0;
	char ver[4] = "";
	char *dummy_ptr = NULL;

	char *data = NULL;
	char con_type[100] = "";
	char str[1024] = "";

	char delimit[] = "\n";


	strcpy(str, string);

	data = strtok(str, delimit);
	sscanf(data,"HTTP/%s %d", ver, code);

	dummy_ptr = data + 13;
	strcpy(error_string, dummy_ptr);

	while(1)
	{
		data = strtok(NULL, delimit);
		if(data == NULL) break;
		if(strncmp(data, "Content-Length", 14) == 0)
		{
			sscanf(data, "Content-Length: %d", &con_len);
			//printf("DW: Info! Content length = %d\n", con_len);
		} else 
		if(strncmp(data, "Content-Type", 12) == 0)
		{
			sscanf(data, "Content-Type: %s", con_type);
			//printf("DW: Info! Content Type = %s\n", con_type);
		}
	}

	return con_len;
}


int _RecvData(int s, char *buffer, int length)
{
	int n = 0;
	n = read(s, buffer, length);
	if(n < 0) perror("DW: Error! recv data");

	return n;
}

int Dw_GetHTTPRequestFile(char *url)
{
	FILE *fp = NULL;

	int s = 0, n = 0;
	int tr = 0;
	int code = 0;
	int length = 0;
	int percent = 0;
	char *dummy = NULL;
	char ip[32] = "";
	char http_req[1024] = ""; 
	char buffer[BUFFER_SIZE] = "";
	char error_string[256] = "";
	char *filename = NULL;

	char http_request_fmt[] = "GET %s HTTP/1.1\n"
	"User-Agent: Prabin's Downloader (ver 1.0)\n"
	"Host: %s:80\n"
	"Accept: text/html, application/xml;q=0.9, application/xhtml+xml, "
	"image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.5\n"
	"Accept-Language: en-us,en;q=0.5\n"
	"Connection: Keep-Alive\n\n";

	if (url == NULL) return -1;
	dummy = _GetIP(url, ip);

	if (dummy == NULL)
	{
		//printf("DW: Error! Lookup: %s failed\n", url);
		return -1;
	}

	filename = basename(url);
	if(filename == NULL)
	{
		printf("DW: Error! filename Invalid\n");
		return -1;
	}

	printf("DW: File: %s\n", filename);

	s = _OpenSocket(ip, port);

	if(s <= 0 ) return -1;
	sprintf(http_req, http_request_fmt, burl.directory, burl.domain,burl);

	printf("DW: Sending request...\n");
	n = _SendString(s, http_req, strlen(http_req));

	memset(buffer,0, BUFFER_SIZE);

	_RecvHeader(s, buffer, BUFFER_SIZE);
	//printf("DW: Received Header. \n");
	length = _parseHeader(buffer, &code, error_string);

	if(code != 200)
	{
		printf("DW: Error! %s\n", error_string);
		close (s);
		return -1;
	}

	printf ("DW: File Size:  %d Bytes\n",length);
	printf("DW: Receiving Data...\n");

	fp = fopen(filename, "w");

	if(fp == NULL) 
	{
		perror ("DW: Error! open");
		close (s);
		return -1;
	}
	
	tr = 0;
	while(tr <= length)
	{
		memset(buffer,0, BUFFER_SIZE);
		n = _RecvData(s, buffer, BUFFER_SIZE);
		fwrite(buffer,1 ,n, fp);
		percent = (int)((tr * 100)  / length ) ; 
		//gotoxy(0,14);
		fprintf(stdout, "%d Bytes out of %d Bytes : %d%%. \r", tr, length, percent);
		fflush(stdout);
		if(n < 0 || tr == length) break;
		tr += n;

	}
	fclose(fp);

	printf("\nDW: Success Download...\n");

	close(s);
	return 0;
}
